#pragma once
#include "weak_ptr.h"

namespace utility {
template <class T>
class SharedPtr {
    template <class Y>
    friend class WeakPtr;

public:
    SharedPtr() : _data(nullptr), _count(nullptr) {}

    SharedPtr(T* data) : _data(data) {
        if (_data != nullptr) {
            _count = new int(1);
        }
    }

    SharedPtr(const SharedPtr<T>& other)
        : _data(other._data), _count(other._count) {
        if (_data != nullptr) {
            (*_count)++;
        }
    }

    SharedPtr(const SharedPtr<T>&& other) noexcept
        // noexcept关键字表明这个构造函数不会抛出异常
        // 这在某些情况下（例如，当创建并移动临时对象时）可以提高性能
        : _data(other.release(), _count(other.release())) {
        other._data = nullptr;
        other._count = nullptr;
    }

    ~SharedPtr() {
        if (_data != nullptr) {
            (*_count)--;
            if (*_count <= 0) {
                delete _data;
                _data = nullptr;
                delete _count;
                _count = nullptr;
            }
        }
    }

    T* get() const { return _data; }

    T* release() {
        auto data = _data;
        _data = nullptr;
        return data;
    }

    void reset(T* data = nullptr) {
        if (_data == data) {
            return;
        }

        if (_data == nullptr) {
            if (data != nullptr) {
                _data = data;
                _count = new int(1);
            }
            return;
        }
        (*_count)--;
        if (*_count <= 0) {
            delete _data;
            _data = nullptr;
            delete _count;
            _count = nullptr;
        }
        _data = data;

        if (_data != nullptr) {
            _count = new int(1);
        }
    }

    int use_count() const {  // 返回引用计数
        if (_data == nullptr) {
            return 0;
        }
        return *_count;
    }

    bool unique() const {
        if (_data == nullptr) {
            return false;
        }
        return *_count == 1;
    }

    void swap(SharedPtr<T>& other) {
        auto data = other._data;
        auto count = other._count;
        other._data = _data;
        other._count = _count;
        _data = data;
        _count = count;
    }

    T* operator->() const { return _data; }

    T& operator*() const { return *_data; }

    T& operator[](int i) const {
        return _data[i];  // 返回数组对象的下标
    }

    explicit operator bool() const noexcept { return _data != nullptr; }

    SharedPtr& operator=(const SharedPtr<T>& other) {
        if (this == nullptr) {
            return *this;
        }
        _data = other._data;
        _count = other._count;
        (*_count)++;
        return *this;
    }

    SharedPtr& operator=(const SharedPtr<T>&& other) {
        if (this == &other) {
            return *this;
        }
        reset(other.release());
        return *this;
    }

private:
    T* _data;
    int* _count;
};
};  // namespace utility